#include "BackupSRAM.h"
#include "string.h"
//备份SRAM大小
#define BACKUP_SRAM_SIZE        (4*1024)

u8 BackupSRAM_Init(void)
{
    RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR, ENABLE);
    PWR_BackupAccessCmd(ENABLE);
    RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_BKPSRAM, ENABLE);
    PWR_BackupRegulatorCmd(ENABLE);

    //备份SRAM的低功耗稳压器已准备就绪
    while(PWR_GetFlagStatus(PWR_FLAG_BRR) == RESET);

    return 1;
}

//u16 BackupSRAM_WriteData(u16 AddrOffset, u8 *pData, u16 DataLen)
//{
//    u32 len;
//无效的地址
//    if(pData==NULL) return 0;
//无效的数量
//    if(DataLen==0) return 0;
//起始地址有误
//    if(AddrOffset >= BACKUP_SRAM_SIZE) return 0;
//限制范围，只有4KB
//    len = AddrOffset + DataLen;

//    if(len > BACKUP_SRAM_SIZE) len = BACKUP_SRAM_SIZE;
//计算要写入的数据长度
//    len -= AddrOffset;

//    memcpy((u8 *)BKPSRAM_BASE+AddrOffset, pData, DataLen);
//
//    return len;
//}


//u16 BackupSRAM_ReadData(u16 AddrOffset, u8 *pData, u16 DataLen)
//{
//    u32 len;

//无效的地址
//    if(pData==NULL) return 0;
//无效的数量
//    if(DataLen==0) return 0;
//起始地址有误
//    if(AddrOffset >= BACKUP_SRAM_SIZE) return 0;

//    len = AddrOffset + DataLen;
//限制范围，只有4KB
//    if(len > BACKUP_SRAM_SIZE) len = BACKUP_SRAM_SIZE;
//计算要写入的数据长度
//    len -= AddrOffset;

//    memcpy(pData, (u8 *)BKPSRAM_BASE+AddrOffset, DataLen);
//
//    return len;
//}



s8 write_to_backup_sram(u8 *data, u16 bytes, u16 offset)
{
    const u16 backup_size = 0x1000;
    u8 *base_addr = (u8 *)BKPSRAM_BASE;
    vu16 i = 0;

    if(bytes + offset >= backup_size)
    {
        /* ERROR : the last byte is outside the backup SRAM region */
        return -1;
    }

    RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_BKPSRAM, ENABLE);
    /* disable backup domain write protection */
    // set RCC->APB1ENR.pwren
    RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR, ENABLE);
    // set PWR->CR.dbp = 1;
    PWR_BackupAccessCmd(ENABLE);
    /** enable the backup regulator (used to maintain the backup SRAM content in
    * standby and Vbat modes). NOTE : this bit is not reset when the device
    * wakes up from standby, system reset or power reset. You can check that
    * the backup regulator is ready on PWR->CSR.brr, see rm p144 */
    // set PWR->CSR.bre = 1;
    PWR_BackupRegulatorCmd(ENABLE);

    for(i = 0; i < bytes; i++)
    {
        *(base_addr + offset + i) = *(data + i);
    }

    PWR_BackupAccessCmd(DISABLE);
    return 0;
}
s8 read_from_backup_sram(u8 *data, u16 bytes, u16 offset)
{
    const u16 backup_size = 0x1000;
    u8 *base_addr = (u8 *)BKPSRAM_BASE;
    vu16 i = 0;

    if(bytes + offset >= backup_size)
    {
        /* ERROR : the last byte is outside the backup SRAM region */
        return -1;
    }

    RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_BKPSRAM, ENABLE);

    for(i = 0; i < bytes; i++)
    {
        *(data + i) = *(base_addr + offset + i);
    }

    return 0;
}
s8 write_to_backup_rtc(u32 *data, u16 bytes, u16 offset)
{
    const u16 backup_size = 80;
    volatile u32 *base_addr = &(RTC->BKP0R);
    vu16 i = 0;

    if(bytes + offset >= backup_size)
    {
        /* ERROR : the last byte is outside the backup SRAM region */
        return -1;
    }
    else if(offset % 4 || bytes % 4)
    {
        /* ERROR: data start or num bytes are not word aligned */
        return -2;
    }
    else
    {
        bytes >>= 2;  /* divide by 4 because writing words */
    }

    /* disable backup domain write protection */
    // set RCC->APB1ENR.pwren
    RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR, ENABLE);
    PWR_BackupAccessCmd(ENABLE);

    for(i = 0; i < bytes; i++)
    {
        *(base_addr + offset + i) = *(data + i);
    }

    PWR_BackupAccessCmd(DISABLE);
    // consider also disabling the power peripherial?
    return 0;
}
s8 read_from_backup_rtc(u32 *data, u16 bytes, u16 offset)
{
    const u16 backup_size = 80;
    volatile u32 *base_addr = &(RTC->BKP0R);
    u16 i;

    if(bytes + offset >= backup_size)
    {
        /* ERROR : the last byte is outside the backup SRAM region */
        return -1;
    }
    else if(offset % 4 || bytes % 4)
    {
        /* ERROR: data start or num bytes are not word aligned */
        return -2;
    }
    else
    {
        bytes >>= 2;  /* divide by 4 because writing words */
    }

    /* read should be 32 bit aligned */
    for(i = 0; i < bytes; i++)
    {
        *(data + i) = *(base_addr + offset + i);
    }

    return 0;
}